/*
 * Wireless Tools
 *
 * Jean II - HPLB 97->99 - HPL 99->09
 *
 * Common header for the Wireless Extension library...
 *
 * This file is released under the GPL license.
 * Copyright (c) 1997-2009 Jean Tourrilhes <jt@hpl.hp.com>
 */

#ifndef __IWLIB_H__
#define __IWLIB_H__

/***************************** INCLUDES *****************************/

/* Standard headers */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h> /* gethostbyname, getnetbyname */
#ifdef ANDROID
#include <net/if_ether.h> /* struct ether_addr */
#else
#include <net/ethernet.h> /* struct ether_addr */
#endif
#include <sys/time.h> /* struct timeval */
#include <unistd.h>

/* This is our header selection. Try to hide the mess and the misery :-(
 * Don't look, you would go blind ;-)
 * Note : compatibility with *old* distributions has been removed,
 * you will need Glibc 2.2 and older to compile (which means 
 * Mandrake 8.0, Debian 2.3, RH 7.1 or older).
 */

/* Set of headers proposed by Dr. Michael Rietz <rietz@mail.amps.de>, 27.3.2 */
#include <net/if_arp.h>     /* For ARPHRD_ETHER */
#include <sys/socket.h>     /* For AF_INET & struct sockaddr */
#include <netinet/in.h>     /* For struct sockaddr_in */
#include <netinet/if_ether.h>

/* Fixup to be able to include kernel includes in userspace.
 * Basically, kill the sparse annotations... Jean II */
#ifndef __user
#define __user
#endif

#include <linux/types.h>        /* for "caddr_t" et al		*/

/* Glibc systems headers are supposedly less problematic than kernel ones */
#include <sys/socket.h>         /* for "struct sockaddr" et al	*/
#include <net/if.h>             /* for IFNAMSIZ and co... */

/* Private copy of Wireless extensions (in this directoty) */
#include "wireless.h"

#ifdef __cplusplus
extern "C" {
#endif

/************************ CONSTANTS & MACROS ************************/
/* Various versions information */
/* Recommended Wireless Extension version */
#define WE_VERSION      22
/* Maximum forward compatibility built in this version of WT */
#define WE_MAX_VERSION  22
/* Version of Wireless Tools */
#define WT_VERSION      30

/****************************** TYPES ******************************/

/* Shortcuts */
typedef struct iw_statistics    iwstats;
typedef struct iw_range         iwrange;
typedef struct iw_param         iwparam;
typedef struct iw_freq          iwfreq;
typedef struct iw_quality       iwqual;
typedef struct iw_priv_args     iwprivargs;
typedef struct sockaddr         sockaddr;

/* Structure for storing all wireless information for each device
 * This is a cut down version of the one above, containing only
 * the things *truly* needed to configure a card.
 * Don't add other junk, I'll remove it... */
typedef struct wireless_config
{
    char            name[IFNAMSIZ + 1];             /* Wireless/protocol name */
    int             has_nwid;
    iwparam         nwid;                           /* Network ID */
    int             has_freq;
    double              freq;                       /* Frequency/channel */
    int             freq_flags;
    int             has_key;
    unsigned char   key[IW_ENCODING_TOKEN_MAX];     /* Encoding key used */
    int             key_size;                       /* Number of bytes */
    int             key_flags;                      /* Various flags */
    int             has_essid;
    int             essid_on;
    char            essid[IW_ESSID_MAX_SIZE + 2];   /* ESSID (extended network) */
    int             essid_len;
    int             has_mode;
    int             mode;                           /* Operation mode */
} wireless_config;

/* Structure for storing all wireless information for each device
 * This is pretty exhaustive... */
typedef struct wireless_info
{
    struct wireless_config    b;    /* Basic information */

    int         has_sens;
    iwparam     sens;               /* sensitivity */
    int         has_nickname;
    char        nickname[IW_ESSID_MAX_SIZE + 2];    /* NickName */
    int         has_ap_addr;
    sockaddr    ap_addr;            /* Access point address */
    int         has_bitrate;
    iwparam     bitrate;            /* Bit rate in bps */
    int         has_rts;
    iwparam     rts;                /* RTS threshold in bytes */
    int         has_frag;
    iwparam     frag;               /* Fragmentation threshold in bytes */
    int         has_power;
    iwparam     power;              /* Power management parameters */
    int         has_txpower;
    iwparam     txpower;            /* Transmit Power in dBm */
    int         has_retry;
    iwparam     retry;              /* Retry limit or lifetime */

    /* Stats */
    iwstats     stats;
    int         has_stats;
    iwrange     range;
    int         has_range;

    /* Auth params for WPA/802.1x/802.11i */
    int         auth_key_mgmt;
    int         has_auth_key_mgmt;
    int         auth_cipher_pairwise;
    int         has_auth_cipher_pairwise;
    int         auth_cipher_group;
    int         has_auth_cipher_group;
} wireless_info;

/* Structure for storing an entry of a wireless scan.
 * This is only a subset of all possible information, the flexible
 * structure of scan results make it impossible to capture all
 * information in such a static structure. */
typedef struct wireless_scan
{
    /* Linked list */
    struct wireless_scan *  next;

    /* Cell identifiaction */
    int         has_ap_addr;
    sockaddr    ap_addr;            /* Access point address */

    /* Other information */
    struct      wireless_config	b;  /* Basic information */
    iwstats     stats;              /* Signal strength */
    int         has_stats;
    iwparam     maxbitrate;         /* Max bit rate in bps */
    int         has_maxbitrate;
} wireless_scan;

/*
 * Context used for non-blocking scan.
 */
typedef struct wireless_scan_head
{
  wireless_scan *   result;         /* Result of the scan */
  int               retry;          /* Retry level */
} wireless_scan_head;

/* Structure used for parsing event streams, such as Wireless Events
 * and scan results */
typedef struct stream_descr
{
  char *    end;        /* End of the stream */
  char *    current;    /* Current event in stream of events */
  char *    value;      /* Current value in event */
} stream_descr;

/* Prototype for handling display of each single interface on the
 * system - see iw_enum_devices() */
typedef int (*iw_enum_handler)(int  skfd,
                    char *  ifname,
                    char *  args[],
                    int     count );

/* Describe a modulation */
typedef struct iw_modul_descr
{
    unsigned int        mask;       /* Modulation bitmask */
    char                cmd[8];     /* Short name */
    char *              verbose;    /* Verbose description */
} iw_modul_descr;

/**************************** PROTOTYPES ****************************/
/*
 * All the functions in iwlib.c
 */

/* ---------------------- SOCKET SUBROUTINES -----------------------*/
int iw_sockets_open(void);
void iw_enum_devices(int    skfd,
                iw_enum_handler fn,
                char *      args[],
                int         count);

/* --------------------- WIRELESS SUBROUTINES ----------------------*/
int iw_get_kernel_we_version(void);
int iw_print_version_info(const char *	toolname);
int iw_get_range_info(int   skfd,const char * ifname,iwrange * range);
int iw_get_priv_info(int skfd,const char * ifname,iwprivargs ** ppriv);
int iw_get_basic_config(int skfd,const char * ifname,wireless_config * info);
int iw_set_basic_config(int skfd,const char * ifname,wireless_config * info);

/* --------------------- PROTOCOL SUBROUTINES --------------------- */
int iw_protocol_compare(const char * protocol1,const char * protocol2);

/* ---------------------- ESSID SUBROUTINES ---------------------- */
void iw_essid_escape(char * dest,const char * src,const int slen);
int iw_essid_unescape(char * dest,const char * src);

/* -------------------- FREQUENCY SUBROUTINES --------------------- */
void    iw_float2freq(double in,iwfreq * out);
double  iw_freq2float(const iwfreq * in);
void    iw_print_freq_value(char * buffer,int buflen,double freq);
void iw_print_freq(char * buffer,
              int       buflen,
              double    freq,
              int       channel,
              int       freq_flags);
int iw_freq_to_channel(double freq,const struct iw_range * range);
int iw_channel_to_freq(int channel,
               double * pfreq,
               const struct iw_range * range);
void iw_print_bitrate(char * buffer,int buflen,int bitrate);

/* ---------------------- POWER SUBROUTINES ----------------------- */
int iw_dbm2mwatt(int in);
int iw_mwatt2dbm(int in);
void iw_print_txpower(char * buffer,int buflen,struct iw_param * txpower);

/* -------------------- STATISTICS SUBROUTINES -------------------- */
int iw_get_stats(int            skfd,
                const char *    ifname,
                iwstats *       stats,
                const iwrange * range,
                int             has_range);
void iw_print_stats(char *          buffer,
                    int             buflen,
                    const iwqual *  qual,
                    const iwrange * range,
                    int             has_range);

/* --------------------- ENCODING SUBROUTINES --------------------- */
void iw_print_key(char *    buffer,
                int         buflen,
                const unsigned char * key,
                int         key_size,
                int         key_flags);
int iw_in_key(const char * input,unsigned char * key);
int iw_in_key_full(int skfd,
                const char *    ifname,
                const char *    input,
                unsigned char * key,
               __u16 *          flags);

/* ----------------- POWER MANAGEMENT SUBROUTINES ----------------- */
void iw_print_pm_value(char * buffer,
                int     buflen,
                int     value,
                int     flags,
                int     we_version);
void iw_print_pm_mode(char * buffer,
                int        buflen,
                int        flags);

/* --------------- RETRY LIMIT/LIFETIME SUBROUTINES --------------- */
void iw_print_retry_value(char *    buffer,
                    int         buflen,
                    int         value,
                    int         flags,
                    int         we_version);

/* ----------------------- TIME SUBROUTINES ----------------------- */
void iw_print_timeval(char *    buffer,
                    int         buflen,
                    const struct timeval *  time,
                    const struct timezone * tz);

/* --------------------- ADDRESS SUBROUTINES ---------------------- */
int iw_check_mac_addr_type(int  skfd,const char * ifname);
int iw_check_if_addr_type(int   skfd,const char * ifname);
char *iw_mac_ntop(const unsigned char * mac,
                    int             maclen,
                    char *          buf,
                    int             buflen);
void iw_ether_ntop(const struct ether_addr * eth,char * buf);
char *iw_sawap_ntop(const struct sockaddr * sap,char * buf);
int iw_mac_aton(const char * orig,unsigned char * mac,int macmax);
int iw_ether_aton(const char* bufp, struct ether_addr* eth);
int iw_in_inet(char *bufp, struct sockaddr *sap);
int iw_in_addr(int              skfd,
            const char *        ifname,
            char *              bufp,
            struct sockaddr *   sap);

/* ----------------------- MISC SUBROUTINES ------------------------ */
int iw_get_priv_size(int args);

/* ---------------------- EVENT SUBROUTINES ---------------------- */
void iw_init_event_stream(struct stream_descr *	stream, char * data, int len);
int iw_extract_event_stream(struct stream_descr *  stream, struct iw_event * iwe, int we_version);

/* --------------------- SCANNING SUBROUTINES --------------------- */
int iw_process_scan(int skfd, char * ifname, int we_version, wireless_scan_head * context);
int iw_scan(int skfd,
            char *  ifname,
            int     we_version,
            wireless_scan_head * context);

/**************************** VARIABLES ****************************/

/* Modes as human readable strings */
extern const char * const       iw_operation_mode[];
#define IW_NUM_OPER_MODE        7
#define IW_NUM_OPER_MODE_EXT    8

/* Modulations as human readable strings */
extern const struct iw_modul_descr  iw_modul_list[];
#define IW_SIZE_MODUL_LIST          16

/************************* INLINE FUNTIONS *************************/
/*
 * Functions that are so simple that it's more efficient inlining them
 * Most inline are private because gcc is fussy about inline...
 */

/*
 * Note : I've defined wrapper for the ioctl request so that
 * it will be easier to migrate to other kernel API if needed
 */

/*------------------------------------------------------------------*/
/*
 * Wrapper to push some Wireless Parameter in the driver
 */
static inline __attribute__((always_inline)) int
iw_set_ext(int          skfd,       /* Socket to the kernel */
        const char *    ifname,     /* Device name */
        int             request,    /* WE ID */
        struct iwreq *  pwrq)       /* Fixed part of the request */
{
    /* Set device name */
    strncpy(pwrq->ifr_name, ifname, IFNAMSIZ);
    /* Do the request */
    return(ioctl(skfd, request, pwrq));
}

/*------------------------------------------------------------------*/
/*
 * Wrapper to extract some Wireless Parameter out of the driver
 */
static inline __attribute__((always_inline)) 
int iw_get_ext(int              skfd,           /* Socket to the kernel */
            const char *        ifname,        /* Device name */
            int                 request,       /* WE ID */
            struct iwreq *      pwrq)           /* Fixed part of the request */
{
    /* Set device name */
    strncpy(pwrq->ifr_name, ifname, IFNAMSIZ);
    /* Do the request */
    return(ioctl(skfd, request, pwrq));
}

/*------------------------------------------------------------------*/
/*
 * Close the socket used for ioctl.
 */
static inline void iw_sockets_close(int	skfd)
{
    close(skfd);
}

#ifdef __cplusplus
}
#endif

#endif  /* IWLIB_H */
